


#include "mcu.h"
#include "same51n20a.h"
#include "debug.h"

static inline void clock_init(void) {
	// 配置外部有源晶振16Mhz
	OSCCTRL_REGS->OSCCTRL_XOSCCTRL[0] =
		OSCCTRL_XOSCCTRL_STARTUP(6) |  // 1952 ms
		OSCCTRL_XOSCCTRL_RUNSTDBY(1) |
		OSCCTRL_XOSCCTRL_ENALC(1) |
		OSCCTRL_XOSCCTRL_IMULT(4) |
		OSCCTRL_XOSCCTRL_IPTAT(3) |
		OSCCTRL_XOSCCTRL_XTALEN(1) |
		OSCCTRL_XOSCCTRL_ENABLE(1);
	while(0 == (OSCCTRL_REGS->OSCCTRL_STATUS & OSCCTRL_STATUS_XOSCRDY0_Msk));

	// 配置锁相环-分频8-2Mhz-倍频系数80-输出160Mhz
    OSCCTRL_REGS->DPLL[0].OSCCTRL_DPLLCTRLB = OSCCTRL_DPLLCTRLB_DIV(3) | OSCCTRL_DPLLCTRLB_REFCLK(OSCCTRL_DPLLCTRLB_REFCLK_XOSC0_Val);
	OSCCTRL_REGS->DPLL[0].OSCCTRL_DPLLRATIO = OSCCTRL_DPLLRATIO_LDRFRAC(0x0) | OSCCTRL_DPLLRATIO_LDR(79);
	OSCCTRL_REGS->DPLL[0].OSCCTRL_DPLLCTRLA = OSCCTRL_DPLLCTRLA_RUNSTDBY(1) | OSCCTRL_DPLLCTRLA_ENABLE(1);
	while(0 == (OSCCTRL_REGS->DPLL[0].OSCCTRL_DPLLSTATUS & OSCCTRL_DPLLSTATUS_CLKRDY_Msk)); 
	
	// 配置GCLK[0]-分频2-80Mhz
	GCLK_REGS->GCLK_GENCTRL[0] =
		GCLK_GENCTRL_DIV(2) |
		GCLK_GENCTRL_RUNSTDBY(1) |
		GCLK_GENCTRL_GENEN(1) |
		GCLK_GENCTRL_SRC_DPLL0 | 
		GCLK_GENCTRL_IDC(1);
	while(1 == (GCLK_REGS->GCLK_SYNCBUSY & GCLK_SYNCBUSY_GENCTRL_GCLK0));

	// 配置GCLK[3]-内部48Mhz
	GCLK_REGS->GCLK_GENCTRL[3] =
		GCLK_GENCTRL_DIV(0) |
		GCLK_GENCTRL_RUNSTDBY(1) |
		GCLK_GENCTRL_GENEN(1) |
		GCLK_GENCTRL_SRC_DFLL |
		GCLK_GENCTRL_IDC(1);
	while(1 == (GCLK_REGS->GCLK_SYNCBUSY & GCLK_SYNCBUSY_GENCTRL_GCLK3));
}

static inline void led_gpio_init(void) {
	PORT_REGS->GROUP[0].PORT_DIRSET = PORT_PA02;
}

static inline void rev_init(void) {
	PORT_REGS->GROUP[0].PORT_DIRCLR = PORT_PA06 | PORT_PA07;
	PORT_REGS->GROUP[0].PORT_PINCFG[PIN_PA06] = PORT_PINCFG_PULLEN(1) | PORT_PINCFG_INEN(1);
	PORT_REGS->GROUP[0].PORT_PINCFG[PIN_PA07] = PORT_PINCFG_PULLEN(1) | PORT_PINCFG_INEN(1);
	PORT_REGS->GROUP[0].PORT_OUTSET = PIN_PA06 | PORT_PA07;
}

static inline void timer_init(void) {
	MCLK_REGS->MCLK_APBAMASK |= MCLK_APBAMASK_TC0(1);
	GCLK_REGS->GCLK_PCHCTRL[TC0_GCLK_ID] = GCLK_PCHCTRL_CHEN(1) | GCLK_PCHCTRL_GEN_GCLK0;
	TC0_REGS->COUNT16.TC_CTRLA = TC_CTRLA_PRESCALER_DIV16 | TC_CTRLA_MODE_COUNT16;
	TC0_REGS->COUNT16.TC_CC[0] = TC_COUNT16_CC_CC(4999);// 9762
	TC0_REGS->COUNT16.TC_INTENSET = TC_INTENSET_MC0(1);
	TC0_REGS->COUNT16.TC_CTRLA |= TC_CTRLA_ENABLE(1);
	while(TC0_REGS->COUNT16.TC_SYNCBUSY & TC_SYNCBUSY_STATUS_Msk);
	NVIC_EnableIRQ(TC0_IRQn);
}

static inline void uart_init(void) {
	PORT_REGS->GROUP[0].PORT_WRCONFIG =
	PORT_WRCONFIG_WRPINCFG(1) |
	PORT_WRCONFIG_WRPMUX(1) |
	PORT_WRCONFIG_PMUX(2) |    /* function C */
	PORT_WRCONFIG_DRVSTR(1) |
	PORT_WRCONFIG_PINMASK(0x0300) | /* PA08 */
	PORT_WRCONFIG_PMUXEN(1);

	MCLK_REGS->MCLK_APBAMASK |= MCLK_APBAMASK_SERCOM0(1);
	GCLK_REGS->GCLK_PCHCTRL[SERCOM0_GCLK_ID_CORE] = GCLK_PCHCTRL_CHEN(1) | GCLK_PCHCTRL_GEN_GCLK0;

	SERCOM0_REGS->USART_INT.SERCOM_CTRLA = 0x00; /* disable SERCOM -> enable config */
	while(SERCOM0_REGS->USART_INT.SERCOM_SYNCBUSY & SERCOM_USART_INT_SYNCBUSY_ENABLE_Msk);

	SERCOM0_REGS->USART_INT.SERCOM_CTRLA =
		SERCOM_USART_INT_CTRLA_SAMPR(0) | /* 0 = 16x / arithmetic baud rate, 1 = 16x / fractional baud rate */
		SERCOM_USART_INT_CTRLA_DORD(1) |     /* LSB first */
		SERCOM_USART_INT_CTRLA_MODE(1) |  /* 0x0 USART with external clock, 0x1 USART with internal clock */
		SERCOM_USART_INT_CTRLA_RXPO(1) |  /* SERCOM PAD[1] is used for data reception */
		SERCOM_USART_INT_CTRLA_TXPO(0);   /* SERCOM PAD[0] is used for data transmission */

	SERCOM0_REGS->USART_INT.SERCOM_CTRLB = SERCOM_USART_INT_CTRLB_TXEN(1)|SERCOM_USART_INT_CTRLB_RXEN(1); /* transmitter enabled */
	SERCOM0_REGS->USART_INT.SERCOM_BAUD = SERCOM_USART_INT_BAUD_BAUD(64026);

	// set rxc interrept
	SERCOM0_REGS->USART_INT.SERCOM_INTENSET = SERCOM_USART_INT_INTENSET_RXC(1);

	SERCOM0_REGS->USART_INT.SERCOM_CTRLA |= SERCOM_USART_INT_CTRLA_ENABLE(1); /* activate SERCOM */
	while(SERCOM0_REGS->USART_INT.SERCOM_SYNCBUSY & SERCOM_USART_INT_SYNCBUSY_ENABLE_Msk); /* wait for SERCOM to be ready */

	NVIC_EnableIRQ(SERCOM0_2_IRQn);
}

void uart_send_str(const char* text) {
	while (*text) {
		SERCOM0_REGS->USART_INT.SERCOM_DATA = *text++;
		while((SERCOM0_REGS->USART_INT.SERCOM_INTFLAG & SERCOM_USART_INT_INTFLAG_TXC_Msk) == 0);
	}
}

void uart_send_bytes(const uint8_t* bytes, uint16_t len) {
	while (len--) {
		SERCOM0_REGS->USART_INT.SERCOM_DATA = *bytes++;
		while((SERCOM0_REGS->USART_INT.SERCOM_INTFLAG & SERCOM_USART_INT_INTFLAG_TXC_Msk) == 0);
	}
}

int16_t uart_receive_block(uint8_t* dataAddr, uint16_t dLen) {
	uint16_t rxLen = 0;
	uint32_t timeout = 0;
	while(1) {
		if(SERCOM0_REGS->USART_INT.SERCOM_INTFLAG & SERCOM_USART_INT_INTFLAG_RXC_Msk) {
			*dataAddr = SERCOM0_REGS->USART_INT.SERCOM_DATA;
			dataAddr++;
			rxLen++;
			if(rxLen >= dLen) {
				break;
			}
			timeout = 0;
		}
		timeout++;
		if(timeout > 600000) {
			return -1;
		}
	}
	return 0;
}

uint8_t tCount = 0;
uint8_t frameFlag = 0;
void TC0_Handler(void) {
	uint32_t flags = TC0_REGS->COUNT16.TC_INTFLAG;
	TC0_REGS->COUNT16.TC_INTFLAG = flags;
	// PORT_REGS->GROUP[0].PORT_OUTTGL = PORT_PA02;
	TC0_REGS->COUNT16.TC_COUNT = 0;

	if(tCount > 0u) {
		tCount--;
		if(tCount == 0u) {
			frameFlag = 1u;
		}
	}
}

uint8_t _uart0RxBuffer[256];
uint16_t _uart0RxCount = 0;
void SERCOM0_2_Handler(void) {
	_uart0RxBuffer[_uart0RxCount] = SERCOM0_REGS->USART_INT.SERCOM_DATA;
	_uart0RxCount++;
	tCount = 10;
}

#include "qdec/qdec.h"

void mcu_init(void) {
    clock_init();
	led_gpio_init();
	rev_init();
	timer_init();
	uart_init();
	qdec_init();
}

// 编码器A相外部中断
void EIC_EXTINT_0_Handler(void) {
	// 清中断标志
	uint32_t intFlag = EIC_REGS->EIC_INTFLAG & 0x1;
	EIC_REGS->EIC_INTFLAG |= intFlag;
	// 调用正交解码服务函数
	qdec_int_service();
}
// 编码器B相外部中断
void EIC_EXTINT_1_Handler(void) {
	// 清中断标志
	uint32_t intFlag = EIC_REGS->EIC_INTFLAG & 0x2;
	EIC_REGS->EIC_INTFLAG |= intFlag;
	// 调用正交解码服务函数
	qdec_int_service();
}
